//
//  Assignment2StaticMemory.cpp
//  sad
//
//  Created by Christopher Kemsley on 2/26/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include <string>

#include "SystemCDefinitions.hpp"

#include "Settings.hpp"
#include "Exception.hpp"
#include "BusInterface.hpp"

#include "ModuleFactory.hpp"
#include "PubSub.hpp"
#include "Codec.hpp"

#include "Log.hpp"




struct Assignment2StaticMemorySettings : public Settings
{
	unsigned	baseAddress ;
	std::string	busSlaveName ;
	
	Assignment2StaticMemorySettings ( std::string const & name )
	:	Settings(name)
	,	baseAddress(0)
	,	busSlaveName()
		{
		add ( "baseAddress" , baseAddress ) ;
		add ( "slaveName" , busSlaveName ) ;
		}
	
	
	virtual void		validate ()
		{
		if ( busSlaveName.size() == 0 )
			ThrowException ( "Assignment2StaticMemorySettings" , "busSlaveName has zero-length" , __FILE__,__LINE__ ) ;
		}
} ;





struct Assignment2StaticMemory : public ConfiguredModel<Assignment2StaticMemorySettings>
{
	Bus::Word	mBuffer	 [512] ;
	
	sc_port < Bus::SlaveInterface >	bus ;
	
	
	
	SC_HAS_PROCESS(Assignment2StaticMemory) ;
	
	Assignment2StaticMemory ( ModelVariant const & name )
	:	ConfiguredModel<Assignment2StaticMemorySettings> ( name )
	,	mBuffer()
	,	bus()
		{
		Subscription < Bus::SlaveInterface >	bus_	( mConfig.busSlaveName ) ;
		bindPortToInterface ( &bus , bus_ ) ;
		
		
		unsigned init [] = {
			0,	0,	0,	0,	0,	0,
			0,	0,	9,	4,	7,	9,
			0,	12,	14,	15,	16,	11,
			0,	2,	3,	4,	5,	6,
			0,	4,	3,	2,	1,	2,
			0,	2,	7,	6,	4,	9 , // 36-count
			
			0,	0,	0,	0,	0,	0,
			0,	0,	9,	4,	7,	9,
			0,	12,	14,	15,	16,	11,
			0,	2,	3,	4,	5,	6,
			0,	4,	3,	2,	1,	2,
			0,	2,	7,	6,	4,	9 , // 36-count
			
			0,0,0,0,0,0,0,0,9,4,7,9,0,12,14,15,16,11,0,2,3,4,5,6,0,4,3,2,1,2,0,2,7,6,4,9 // doesn't matter
		} ;
		
		unsigned * here = init ;
		unsigned * end = here + 108 ;
		Bus::Word * next = mBuffer ;
		while ( here < end )
			*(next++) = *(here++) ;
		
		
		SC_THREAD ( loop ) ;
		}
	
	
	void	loop ()
		{
		while ( 1 )
			{
			Bus::Request	request ;
			
			while ( 1 )
				{
				bus -> waitForNewRequest ( request ) ;
				
				request . baseAddress -= mConfig.baseAddress ;
				
				if ( request.baseAddress < 108 )
					if ( request.baseAddress+request.blockLength <= 108 )
						{
						bus -> acknowledgeRequest() ;
						break ;
						}
				}
			
			
			unsigned	here	=	request.baseAddress ;
			unsigned	end		=	here + request.blockLength ;
			Bus::Word	word ;
			
			if ( request.operation == Bus::kOperationWrite )
				{
				while ( here < end )
					{
					bus ->readWord ( word ) ;
					mBuffer [here++] = word ;
					}
				}
			else
				{
				while ( here < end )
					{
					word = mBuffer [here++] ;
					bus -> writeWord ( word ) ;
					}
				}
			}
		}
} ;





TypedModuleMaker<Assignment2StaticMemory>	_Assignment2StaticMemory ( "assignment2.memory" ) ;
